import React, { useEffect, useState } from 'react';
import { Box, GridLegacy as Grid } from '@mui/material';
import { useAppDispatch } from '../../redux/hooks';
import { openDialog } from '../../redux/slices/generalSlice';
import { replayAll } from '../general/CommandRecorder';
import Drawer from '../Drawer';
import Topbar from '../Topbar';
import Layout from '../Layout/Layout';
import Dialog from '../Dialog/Dialog';
import ConfirmationDialog from '../Dialog/ConfirmationDialog';
import ErrorDialog from '../Dialog/ErrorDialog';

// Extend window interface for Geppetto
declare global {
  interface Window {
    GEPPETTO?: any;
    addEventListener(type: 'kernelstatus', listener: (event: CustomEvent) => void): void;
  }
}

const NetPyNE: React.FC = () => {
  const dispatch = useAppDispatch();
  const [kernelRestartState, setKernelRestartState] = useState({
    state: 'idle' as 'idle' | 'init' | 'restarting' | 'special_restart',
    kernelID: undefined as string | undefined,
    crashLoop: false as boolean | number,
  });

  useEffect(() => {
    // Register Geppetto event handlers
    const openPythonCallDialog = (event: any) => {
      if (event?.evalue && event?.traceback) {
        dispatch(openDialog({
          title: 'Python Error',
          message: event.evalue,
        }));
      } else if (event?.data?.response?.evalue) {
        dispatch(openDialog({
          title: 'Python Error',
          message: event.data.response.evalue,
        }));
      }
    };

    if (window.GEPPETTO) {
      window.GEPPETTO.on(window.GEPPETTO.Events.Error_while_exec_python_command, openPythonCallDialog);
    }

    // Kernel restart handling
    const handleKernelRestart = (event: CustomEvent) => {
      const { kernel, type } = event.detail;
      
      switch (kernelRestartState.state) {
        case 'restarting':
          if (type === 'kernel_ready' || type === 'kernel_autorestarting') {
            console.log('Replaying all commands since the beginning of the session');
            replayAll(kernelRestartState.kernelID || '');
            setKernelRestartState({
              ...kernelRestartState,
              state: 'idle',
              kernelID: undefined,
            });
          }
          break;
        case 'idle':
          if (type === 'kernel_connected') {
            console.log('Kernel is connecting/starting, being init');
            setKernelRestartState({
              ...kernelRestartState,
              state: 'init',
              kernelID: kernel.id,
            });
          } else if (type === 'kernel_autorestarting') {
            console.log('Kernel restart event caught, trying to re-init the current model');
            setKernelRestartState({
              ...kernelRestartState,
              state: 'restarting',
              kernelID: kernel.id,
            });
            if (!kernelRestartState.crashLoop) {
              dispatch(openDialog({
                title: 'Kernel restart',
                message: 'An action occurred that made the kernel restart. We are reloading your model and all the actions you applied on it.',
              }));
            }
          } else if (type === 'kernel_restarting') {
            console.log('Kernel restart, perhaps it\'s a special restart?');
            setKernelRestartState({
              ...kernelRestartState,
              state: 'special_restart',
              kernelID: kernel.id,
            });
          }
          break;
        case 'init':
          if (type === 'kernel_ready') {
            console.log('Kernel properly initialized');
            setKernelRestartState({
              ...kernelRestartState,
              state: 'idle',
              kernelID: undefined,
            });
          }
          break;
        case 'special_restart':
          if (type === 'kernel_autorestarting') {
            console.log('Kernel autorestart after a start, we might not have the ready event, we force it then');
            replayAll(kernelRestartState.kernelID || '');
            setKernelRestartState({
              ...kernelRestartState,
              state: 'restarting',
              kernelID: kernel.id,
            });
          } else {
            console.log('Regular restart detected');
            setKernelRestartState({
              ...kernelRestartState,
              state: 'idle',
              kernelID: undefined,
            });
          }
          break;
      }
    };

    // Dedicated code to handle crash loops
    const kernelRestartLoopHandler = () => {
      if (!kernelRestartState.crashLoop) {
        dispatch(openDialog({
          title: 'Kernel restart loop stabilization',
          message: 'One of your actions triggered a kernel restart loop. We are trying to identify the faulty command and to restore your model until this point. Close this window and wait for the kernel stabilization notification.',
        }));
      } else {
        clearTimeout(kernelRestartState.crashLoop as number);
      }
      const taskID = setTimeout(() => {
        dispatch(openDialog({
          title: 'Kernel restart loop stabilized',
          message: 'The kernel is now stabilized.',
        }));
        setKernelRestartState({
          ...kernelRestartState,
          crashLoop: false,
        });
      }, 8000) as unknown as number;
      setKernelRestartState({
        ...kernelRestartState,
        crashLoop: taskID,
      });
    };

    window.addEventListener('kernelstatus', handleKernelRestart as EventListener);
    window.addEventListener('kernelRestartLoop', kernelRestartLoopHandler);

    return () => {
      if (window.GEPPETTO) {
        window.GEPPETTO.off(window.GEPPETTO.Events.Error_while_exec_python_command, openPythonCallDialog);
      }
      window.removeEventListener('kernelstatus', handleKernelRestart as EventListener);
      window.removeEventListener('kernelRestartLoop', kernelRestartLoopHandler);
      if (kernelRestartState.crashLoop) {
        clearTimeout(kernelRestartState.crashLoop as number);
      }
    };
  }, [dispatch, kernelRestartState]);

  return (
    <Box
      sx={{
        height: '100%',
        overflow: 'hidden',
        display: 'flex',
        flex: 1,
        flexDirection: 'column',
      }}
    >
      <Box sx={{ position: 'relative', zIndex: (theme) => theme.zIndex.drawer }}>
        <Topbar />
      </Box>
      <Box sx={{ flexGrow: 1, display: 'flex', flexDirection: 'row', position: 'relative', p: 1 }}>
        <Grid container spacing={1} sx={{ display: 'flex', flex: 1, alignItems: 'stretch' }}>
          <Grid item sx={{ flexGrow: 0 }}>
            <Drawer />
          </Grid>
          <Grid item sx={{ flex: 1 }}>
            <Layout />
          </Grid>
        </Grid>
      </Box>
      <Dialog />
      <ConfirmationDialog />
      <ErrorDialog />
    </Box>
  );
};

export default NetPyNE;

